package com.res;

import antlr.ParseTree;
import org.antlr.runtime.ANTLRFileStream;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;

import br.com.porcelli.parser.plsql.PLSQLLexer;
import br.com.porcelli.parser.plsql.PLSQLParser;
import org.antlr.runtime.tree.CommonTree;

import java.io.IOException;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        // write your code here
        String fn = "/u01/home/xuzj/xuzj/dev/plsqltrans/test/Absence_Action_API.pkb";
        fn = "/u01/home/xuzj/xuzj/test.txt";
        parse(fn);
    }


    public static void parse(String file) {
        try {
            PLSQLLexer lex = new PLSQLLexer(new ANTLRNoCaseFileStream(file));
            CommonTokenStream tokens = new CommonTokenStream(lex);
            PLSQLParser parser = new PLSQLParser(tokens);

            /*start_rule_return AST =*/
            //parser.data_manipulation_language_statements();

            //PLSQLParser.create_package_return aPackage = parser.create_package();
            //CommonTree tree = (CommonTree) aPackage.getTree();

            PLSQLParser.create_function_body_return function_body = parser.create_function_body();
            CommonTree tree = (CommonTree) function_body.getTree();
            //System.out.println("tree children cont: "+tree.getText());
            StringBuffer s1=new StringBuffer();
            //process_pkg_spec(tree);
            printTree(tree,s1);
            System.out.println(s1.toString());

            if (parser.getNumberOfSyntaxErrors() != 0) {
                //System.exit(1);
            }

        } catch (RecognitionException e) {
            System.err.println(e.toString());
        } catch (IOException e) {
            System.err.println(e.toString());
        } catch (java.lang.OutOfMemoryError e) {
            System.err.println(file + ":");
            System.err.println(e.toString());
        } catch (java.lang.ArrayIndexOutOfBoundsException e) {
            System.err.println(file + ":");
            System.err.println(e.toString());
        }
    }


    public static void printTree(CommonTree ct,StringBuffer res){
        int i=0;
        res.append("{ \"obj\":\""+ct.getText()+"\"");
        List<CommonTree> childre2n = (List<CommonTree>) ct.getChildren();
        if(childre2n!=null) {
            res.append(",\"ch\":[");
            for (CommonTree ct2 : childre2n) {
                printTree(ct2,res);
                i++;
                if(i<childre2n.size()){
                    res.append(",");
                }
            }
            res.append("]");
        }
        res.append("}");
    }

    public static void process_variable(CommonTree ct,StringBuffer data){
        List<CommonTree> childre2n = (List<CommonTree>) ct.getChildren();
        if(childre2n!=null) {
            for (CommonTree ct2 : childre2n) {
                switch (ct2.getText()){
                    case "VARIABLE_NAME":
                        data.append("    "+ct2.getChild(0).getText());
                        break;
                    case "NATIVE_DATATYPE":
                        data.append("  "+ct2.getChild(0).getText());
                        if(ct2.getChildCount()>1){
                            List<CommonTree> cdatas =  (List<CommonTree>) ct2.getChildren();
                            for(CommonTree cd: cdatas){
                                switch (cd.getText()){
                                    case "PRECISION":
                                        data.append("("+cd.getChild(0).getText()+")");
                                }
                            }
                        }
                        break;
                    case "CONSTANT":
                        data.append("  CONSTANT");
                        break;
                    case "DEFAULT_VALUE":
                        if(ct2.getChildCount()>0){
                            data.append("  :=");
                            List<CommonTree> cdatas =  (List<CommonTree>) ct2.getChildren();
                            for(CommonTree cd: cdatas){
                                switch (cd.getText()){
                                    case "EXPR":
                                        data.append(cd.getChild(0).getText());
                                }
                            }
                        }
                        break;
                }
            }
            data.append(";\n");
        }
    }

    public static void process_procedure(CommonTree ct,StringBuffer data){
        List<CommonTree> childre2n = (List<CommonTree>) ct.getChildren();
        if(childre2n!=null) {
            for (CommonTree ct2 : childre2n) {
                switch (ct2.getText()){
                    case "PROCEDURE_NAME":
                        data.append("\n    Procedure "+ct2.getChild(0).getText());
                        break;
                    case "PARAMETERS":
                        if(ct2.getChildCount()>0){
                            List<CommonTree> params =  (List<CommonTree>) ct2.getChildren();
                            for(CommonTree param: params){
                                data.append("(\n");
                                data.append("        ");
                                List<CommonTree> paramInfos = (List<CommonTree>) param.getChildren();
                                for(CommonTree pInfo:paramInfos) {
                                    switch (pInfo.getText()) {
                                        case "PARAMETER_NAME":
                                            data.append(pInfo.getChild(0).getText());
                                            break;
                                        case "IN":
                                            data.append("  IN");
                                            break;
                                        case "OUT":
                                            data.append("  OUT");
                                            break;
                                        case "NATIVE_DATATYPE":
                                            data.append("  "+pInfo.getChild(0).getText());
                                            break;
                                    }
                                }
                                if(!(params.indexOf(param)==params.size()-1)){
                                    data.append(",\n");
                                }else{
                                    data.append(")");
                                }
                            }
                        }
                        break;
                }
            }
            data.append(";\n");
        }
    }

    public static void process_function(CommonTree ct,StringBuffer data){
        List<CommonTree> childre2n = (List<CommonTree>) ct.getChildren();
        if(childre2n!=null) {
            String retClause ="";
            for (CommonTree ct2 : childre2n) {
                switch (ct2.getText()){
                    case "FUNCTION_NAME":
                        data.append("\n    Function "+ct2.getChild(0).getText());
                        break;
                    case "NATIVE_DATATYPE":
                        retClause=" return "+ ct2.getChild(0).getText();
                        break;
                    case "PARAMETERS":
                        if(ct2.getChildCount()>0){
                            List<CommonTree> params =  (List<CommonTree>) ct2.getChildren();
                            for(CommonTree param: params){
                                data.append("(\n");
                                data.append("        ");
                                List<CommonTree> paramInfos = (List<CommonTree>) param.getChildren();
                                for(CommonTree pInfo:paramInfos) {
                                    switch (pInfo.getText()) {
                                        case "PARAMETER_NAME":
                                            data.append(pInfo.getChild(0).getText());
                                            break;
                                        case "IN":
                                            data.append("  IN");
                                            break;
                                        case "OUT":
                                            data.append("  OUT");
                                            break;
                                        case "NATIVE_DATATYPE":
                                            data.append("  "+pInfo.getChild(0).getText());
                                            break;
                                    }
                                }
                                if(!(params.indexOf(param)==params.size()-1)){
                                    data.append(",\n");
                                }else{
                                    data.append(")");
                                }
                            }
                        }
                        break;
                }
            }
            data.append(retClause + ";\n");
        }
    }

    public static void process_pkg_spec(CommonTree ct){
        StringBuffer sdata=new StringBuffer();
        String pkgName="";
        if("CREATE".equals(ct.getText())){
            List<CommonTree> childre2n = (List<CommonTree>) ct.getChildren();
            if(childre2n!=null) {
                sdata.append("Create or Replace Package ");
                for (CommonTree ct2 : childre2n) {
                    switch (ct2.getText()){
                        case "PACKAGE_NAME":
                            if("".equals(pkgName)){
                                pkgName = ct2.getChild(0).getText();
                                sdata.append(pkgName+" is \n\n");
                            }
                            break;
                        case "VARIABLE_DECLARE":
                            process_variable(ct2,sdata);
                            break;
                        case "PROCEDURE":
                            process_procedure(ct2,sdata);
                            break;
                        case "FUNCTION":
                            process_function(ct2,sdata);
                            break;
                    }
                }
                sdata.append("\nEnd "+pkgName+";\n");
            }
        }
        System.out.println(sdata.toString());
    }

    static class ANTLRNoCaseFileStream extends ANTLRFileStream {
        public ANTLRNoCaseFileStream(String fileName) throws IOException {
            super(fileName, null);
        }

        public ANTLRNoCaseFileStream(String fileName, String encoding)
                throws IOException {
            super(fileName, encoding);
        }

        public int LA(int i) {
            if (i == 0) {
                return 0; // undefined
            }
            if (i < 0) {
                i++; // e.g., translate LA(-1) to use offset 0
            }
            if ((p + i - 1) >= n) {
                return CharStream.EOF;
            }
            return Character.toLowerCase(data[p + i - 1]);
        }
    }
}
